﻿using DotNetty.Codecs;
using DotNetty.Handlers.Logging;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using InkjetControl.codec.codes;
using InkjetControl.NLog;
using InkjetControl.services.handler;
using System;
using System.Configuration;
using System.Threading;
using System.Threading.Tasks;

namespace InkjetControl.services
{
    public class Server
    {

        public EventWaitHandle EventWaitHandler { get; } = new EventWaitHandle(false, EventResetMode.AutoReset);

        public async Task RunServerAsync()
        {
            int port = 6008;
            string p = ConfigurationManager.AppSettings["ServerPort"];
            if (p != null && !"".Equals(p))
            {
                port = int.Parse(p);
            }
            Log.Logger.Info("RunServerAsync start");
            MultithreadEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1);
            MultithreadEventLoopGroup workerGroup = new MultithreadEventLoopGroup();
            try
            {
                ServerBootstrap bootstrap = new ServerBootstrap()
                    .Group(bossGroup, workerGroup)
                    .Channel<TcpServerSocketChannel>()
                    .Option(ChannelOption.SoBacklog, 1024)
                    .Option(ChannelOption.TcpNodelay, true)
                    .Option(ChannelOption.SoKeepalive, true)
                    //.Handler(new LoggingHandler("LSTN"))
                    .ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>
                    {
                        IChannelPipeline pipeline = channel.Pipeline
                        .AddLast(new LengthFieldBasedFrameDecoder(Constants.MAX_FRAME_LENGTH, 0, 4, 0, 4))
                        .AddLast(new LengthFieldPrepender(Constants.LENGTH_FIELD_LENGTH))
                        .AddLast(new NettyBase64Encoder())
                        .AddLast(new NettyBase64Decoder())
                        //
                        .AddLast(new MessageEncoder())
                        .AddLast(new MessageDecoder())
                        //
                        //.AddLast(new LoggingHandler("CONN"))
                        .AddLast(new ServerMessageHandler());
                    }));

                IChannel boundChannel = await bootstrap.BindAsync(port);

                //线程阻塞在这
                _ = EventWaitHandler.WaitOne();

                //关闭服务
                await boundChannel.CloseAsync();
                Log.Logger.Info("RunServerAsync Exit:");
            }
            catch(Exception ex)
            {
                Log.Logger.Error(ex, "RunServerAsync ERROR:");
            }
            finally
            {
                await Task.WhenAll(
                    bossGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)),
                    workerGroup.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1))
                    );
            }
        }

        public void OnExit()
        {
            Log.Logger.Info("RunServerAsync on Exit:");
            EventWaitHandler.Set();
            EventWaitHandler.Close();
            EventWaitHandler.Dispose();
        }
    }
}
